package cn.tedu.submarine;

import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer; //定时器
import java.util.TimerTask;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

public class World extends JPanel{
    //静态常量
    public static final int WIDTH = 641;  // 窗口的宽
    public static final int HEIGHT = 479; // 窗口的高
    public static final int RUNNING = 0;  //运行状态
    public static final int PAUSE = 1;    //暂停状态
    public static final int GAME_OVER = 2;//游戏结束状态
    private int state = RUNNING;          //当前状态(默认运行状态)

    private Battleship ship = new Battleship(); // 战舰对象
    private SeaObject[] submarines = {}; //潜艇数组
    private Mine[] mines = {}; //水雷数组
    private Bomb[] bombs = {}; //炸弹数组

    //生成潜艇对象
    private SeaObject nextSubmarine(){
        Random rand = new Random();
        int type = rand.nextInt(20);
        if(type<10){
            return new ObserveSubmarine();
        }else if(type<16){
            return new TorpedoSubmarine();
        }else{
            return new MineSubmarine();
        }
    }

    //潜艇(侦查潜艇、鱼雷潜艇、水雷潜艇)入场
    private int subEnterIndex = 0;
    private void submarineEnterAction(){
        subEnterIndex++;
        if(subEnterIndex%40==0){ //400毫秒
            //获取潜艇对象
            SeaObject obj = nextSubmarine();
            //扩容
            submarines = Arrays.copyOf(submarines, submarines.length + 1);
            //将obj添加到submarines的最后一个下标位置
            submarines[submarines.length-1] = obj;
        }
    }

    //水雷入场
    private int mineEnterIndex = 0;
    private void mineEnterAction(){
        mineEnterIndex ++;
        if(mineEnterIndex%100==0){
            for(int i = 0;i<submarines.length;i++){
                if(submarines[i] instanceof MineSubmarine){
                    Mine mine = ((MineSubmarine) submarines[i]).shootMine();
                    mines = Arrays.copyOf(mines,mines.length+1);
                    mines[mines.length-1] = mine;
                }
            }
        }
    }

    //海洋对象移动
    private void moveAction(){
        for(int i = 0;i<submarines.length;i++){
            submarines[i].move();
        }
        for(int i = 0;i<mines.length;i++){
            mines[i].move();
        }
        for(int i = 0;i< bombs.length;i++){
            bombs[i].move();
        }
    }

    //删除越界的海洋对象
    private void outOfBoundsAction(){
        for(int i = 0;i<submarines.length;i++){
            if(submarines[i].isOutOfBounds() || submarines[i].isDead()){
                // 将越界元素替换为最后一个元素
                submarines[i] = submarines[submarines.length-1];
                submarines = Arrays.copyOf(submarines,submarines.length-1);
            }
        }
        for(int i = 0;i<mines.length;i++){
            if(mines[i].isOutOfBounds() || mines[i].isDead()){
                mines[i] = mines[mines.length-1];
                mines = Arrays.copyOf(mines,mines.length-1);
            }
        }
        for(int i = 0;i< bombs.length;i++){
            if(bombs[i].isOutOfBounds() || bombs[i].isDead()){
                bombs[i] = bombs[bombs.length-1];
                bombs = Arrays.copyOf(bombs,bombs.length-1);
            }
        }
    }

    //初始玩家得分
    private int score = 0;
    //炸弹与潜艇碰撞
    private void bombBandAction(){//每10毫秒走一次
        for(int i =0;i<bombs.length;i++){
            Bomb b = bombs[i];
            for(int j = 0;j<submarines.length;j++){
                SeaObject s = submarines[j];
                if(b.isLive() && s.isLive() && s.isHit(b)){//若都活着并且还撞上了
                    s.goDead();
                    b.goDead();
                    if(s instanceof EnemyScore){
                        EnemyScore es = (EnemyScore) s;
                        score += es.getScore();//玩家得分
                    }
                    if(s instanceof EnemyLife){
                        EnemyLife el = (EnemyLife) s;
                        int num = el.getLife();//获取命数
                        ship.addLife(num); //给战舰增命
                    }
                }
            }
        }
    }

    private void mineBangAction(){
        for(int i =0;i<mines.length;i++){
            Mine m = mines[i];
            if(m.isLive() && ship.isLive() && m.isHit(ship)){//若都活着并且还撞上了
                m.goDead();
                ship.subtractLife();
            }
        }
    }

    //检测游戏结束
    private void checkGameOverAction(){
        if(ship.getLife() <= 0){
            state = GAME_OVER;
        }
    }

    //启动程序的执行
    private void action() {
        //游戏开始，先询问是否读取存档
        File file = new File("game.sav");
        if(file.exists()){//判断存档文件是否存在
            //若存档文件存在，则询问用户是否读取存档
            int r = JOptionPane.showConfirmDialog(//在当前游戏窗口前弹出一个确认框
                    World.this,//参数1:确认框在游戏窗口上弹出
                    "是否读取存档?"       //参数2:确认框上的提示文字
            );
            if(r == JOptionPane.YES_OPTION){//如果用户点击的“是”这个按钮
                //读取存档
                try {
                    FileInputStream fis = new FileInputStream(file);
                    ObjectInputStream ois = new ObjectInputStream(fis);
                    GameInfo gameInfo = (GameInfo) ois.readObject();
                    ship = gameInfo.getShip();
                    submarines = gameInfo.getSubmarines();
                    mines = gameInfo.getMines();
                    bombs = gameInfo.getBombs();
                    subEnterIndex = gameInfo.getSubEnterIndex();
                    mineEnterIndex = gameInfo.getMineEnterIndex();
                    score = gameInfo.getScore();
                    ois.close();
                } catch (Exception e) {}
            }else if(r == JOptionPane.NO_OPTION || r == JOptionPane.CANCEL_OPTION){
                state = RUNNING;
            }
        }
        //键盘侦听器
        KeyAdapter k = new KeyAdapter() {
            //重写keyReleased() 按键抬起事件  keyPressed()键盘按下事件
            @Override
            public void keyReleased(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_P) {//若抬起的是空格键
                    state = PAUSE;
                    int r = JOptionPane.showConfirmDialog(//在当前游戏窗口前弹出一个确认框
                            World.this,//参数1:确认框在游戏窗口上弹出
                            "保存游戏吗?"       //参数2:确认框上的提示文字
                    );
                    if(r == JOptionPane.YES_OPTION){
                        GameInfo gameInfo = new GameInfo(
                                ship, submarines, mines, bombs,
                                subEnterIndex, mineEnterIndex, score
                        );
                        try {
                            FileOutputStream fos = new FileOutputStream("game.sav");
                            ObjectOutputStream oos = new ObjectOutputStream(fos);
                            oos.writeObject(gameInfo);//将当前游戏的所有数据写入文件保存
                            oos.close();
                            state = RUNNING;//550 10

                        } catch (Exception ex) {}
                    }else if(r == JOptionPane.NO_OPTION || r == JOptionPane.CANCEL_OPTION){
                        state = RUNNING;
                    }
                }
                if(state == RUNNING){
                    if (e.getKeyCode() == KeyEvent.VK_SPACE) {//若抬起的是空格键
                        Bomb obj = ship.shootBomb();
                        bombs = Arrays.copyOf(bombs, bombs.length + 1);
                        bombs[bombs.length - 1] = obj;
                    }
                }
            }
            @Override
            public void keyPressed(KeyEvent e) {
                if(state == RUNNING){
                    if(e.getKeyCode() == KeyEvent.VK_LEFT){
                        ship.moveLeft();
                        if(ship.x<0){
                            ship.x = 0;
                        }
                    }
                    if(e.getKeyCode() == KeyEvent.VK_RIGHT){
                        ship.moveRight();
                        if(ship.x>WIDTH){
                            ship.x = 0;
                        }
                    }
                }
             }
        };
        //添加侦听
        this.addKeyListener(k);

        Timer timer = new Timer();//定时器对象
        int interval = 10; //定时间隔(以毫秒为单位)
        //定时日程表
        timer.schedule(new TimerTask(){
            public void run() {
                //潜艇(侦查潜艇、鱼雷潜艇、水雷潜艇)入场
                if(state == RUNNING){
                    submarineEnterAction();
                    mineEnterAction();
                    moveAction();
                    outOfBoundsAction();
                    bombBandAction();
                    mineBangAction();
                    checkGameOverAction();
                    //重画---系统自动调用paint()方法
                    repaint();
                }
            }
        },interval,interval);
    }

    //重写paint()方法  g:系统自带的画笔
    public void paint(Graphics g){
        Images.sea.paintIcon(null,g,0,0);//画海洋
        ship.paintImage(g);
        for (int i = 0;i< submarines.length;i++) {//遍历所有的战舰
            submarines[i].paintImage(g);
        }
        for (int i = 0;i< mines.length;i++) { //遍历所有的水雷
            mines[i].paintImage(g);
        }
        for (int i = 0;i< bombs.length;i++) { //遍历炸弹
            bombs[i].paintImage(g);
        }
        g.drawString("SCORE:"+score,200,50);
        g.drawString("LIFE:"+ship.getLife(),400,50);


        if(state == GAME_OVER){
            Images.gameover.paintIcon(null,g,0,0);
        }
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        World world = new World();
        world.setFocusable(true);
        frame.add(world);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(World.WIDTH+16,World.HEIGHT+39);
        frame.setLocationRelativeTo(null);
        //系统自动调用paint()方法
        frame.setVisible(true);
        //启动程序的执行
        world.action();
    }
}